from datetime import datetime

from django.db import transaction
from django.http import JsonResponse
from django.views import View
from rest_framework import status
from rest_framework.parsers import JSONParser

from jqdelivery.error import UserExpressNullErr, UserDeliveryNullErr
from jqdelivery.models import (
    UserExpressInfo,
    UserExpress,
    UserDeliveryOrderState,
    UserDeliveryOrder,
)
from jqdelivery.serializers import (
    UserExpressInfoSerializer,
    CreateUserExpressInfoSerializer,
    UpdateUserExpressInfoSerializer,
    UserDeliveryOrderListSerializer,
    UserDeliveryOrderDetailedSerializer,
)
from jqpage.pagination import JQPagination
from juqiadmin.auth import login_auth
from juqiadmin.common.filters import (
    StringFilterResolver,
    join_filters,
    EnumFilterResolver,
)
from wxuser.utli import get_current_user


def _get_user_express(user, lock=False):
    _query_set = UserExpress.objects.filter(deleted=False).filter(user_uuid=user.uuid)
    if lock:
        _query_set = _query_set.select_for_update()
    user_express = _query_set.first()
    return user_express


class UserExpressView(View):
    _filters = {
        "uuid": StringFilterResolver(),
    }

    @login_auth
    def get(self, request, *args, **kwargs):
        user = get_current_user(request, False)
        _query_set = UserExpressInfo.objects.filter(deleted=False).filter(
            user_uuid=user.uuid
        )
        _query_set = join_filters(_query_set, request, self._filters)
        user_express_info = _query_set.first()

        if user_express_info is None:
            raise UserExpressNullErr

        user_express = _get_user_express(user)

        if user_express is None:
            raise UserExpressNullErr

        default = user_express.default_uuid == user_express_info.uuid

        user_express_info_data = UserExpressInfoSerializer(user_express_info).data

        return JsonResponse(
            {
                "code": 0,
                "msg": "ok",
                "data": {"express": user_express_info_data, "default": default},
            },
            status=status.HTTP_200_OK,
        )

    @login_auth
    @transaction.atomic()
    def post(self, request, *args, **kwargs):
        user = get_current_user(request, False)

        request_data: dict = JSONParser().parse(request)
        default = request_data.get("default")
        if default is None:
            default = False

        express_data = request_data.get("express")
        if express_data is None:
            raise UserExpressNullErr

        _query_set = UserExpress.objects.filter(deleted=False).filter(
            user_uuid=user.uuid
        )
        user_express = _query_set.select_for_update().first()
        if user_express is None:
            user_express = UserExpress.objects.create(user_uuid=user.uuid)  # 如果不存就创建

        user_express_info_ser = CreateUserExpressInfoSerializer(data=express_data)
        express_is_valid = user_express_info_ser.is_valid()  # 校验
        if not express_is_valid:
            raise UserExpressNullErr

        express_validated_data = user_express_info_ser.validated_data
        express = UserExpressInfo.objects.create(
            user_uuid=user.uuid,
            express_uuid=user_express.uuid,
            express_name=express_validated_data["express_name"],
            express_phone=express_validated_data["express_phone"],
            express_area=express_validated_data["express_area"],
            express_address=express_validated_data["express_address"],
        )
        if express is None:
            raise UserExpressNullErr

        if default:
            user_express.default_uuid = express.uuid
            user_express.save()

        return JsonResponse(
            {"code": 0, "msg": "ok"},
            status=status.HTTP_200_OK,
        )

    @login_auth
    @transaction.atomic()
    def put(self, request, *args, **kwargs):
        user = get_current_user(request, False)

        request_data: dict = JSONParser().parse(request)
        default = request_data.get("default")
        if default is None:
            default = False

        express_data = request_data.get("express")
        if express_data is None:
            raise UserExpressNullErr

        _query_set = UserExpress.objects.filter(deleted=False).filter(
            user_uuid=user.uuid
        )
        user_express = _query_set.select_for_update().first()
        if user_express is None:
            raise UserExpressNullErr
        user_express_info_ser = UpdateUserExpressInfoSerializer(data=express_data)

        express_is_valid = user_express_info_ser.is_valid()  # 校验
        if not express_is_valid:
            raise UserExpressNullErr

        express_validated_data = user_express_info_ser.validated_data

        express = (
            UserExpressInfo.objects.filter(deleted=False)
            .filter(uuid=express_data["uuid"])
            .filter(user_uuid=user.uuid)
            .filter(express_uuid=user_express.uuid)
            .select_for_update()
            .first()
        )
        if express is None:
            raise UserExpressNullErr

        express.express_uuid = user_express.uuid
        express.express_name = express_validated_data["express_name"]
        express.express_phone = express_validated_data["express_phone"]
        express.express_area = express_validated_data["express_area"]
        express.express_address = express_validated_data["express_address"]

        if default:
            user_express.default_uuid = express.uuid
            user_express.save()

        express.save()

        return JsonResponse(
            {"code": 0, "msg": "ok"},
            status=status.HTTP_200_OK,
        )

    @login_auth
    @transaction.atomic()
    def delete(self, request, *args, **kwargs):
        user = get_current_user(request, False)
        data = JSONParser().parse(request)
        uuid = data.get("uuid", None)
        if uuid is None:
            raise UserExpressNullErr
        _query_set = UserExpress.objects.filter(deleted=False).filter(
            user_uuid=user.uuid
        )
        user_express = _query_set.select_for_update().first()
        _query_set = (
            UserExpressInfo.objects.filter(deleted=False)
            .filter(user_uuid=user.uuid)
            .filter(uuid=uuid)
        )

        express = _query_set.first()

        count = (
            UserExpressInfo.objects.filter(deleted=False)
            .filter(user_uuid=user.uuid)
            .filter(uuid=uuid)
            .update(deleted=True)
        )

        if user_express.default_uuid == express.uuid:
            user_express_info = (
                UserExpressInfo.objects.filter(deleted=False)
                .filter(user_uuid=user.uuid)
                .filter(express_uuid=user_express.uuid)
                .first()
            )
            user_express_info_uuid = None
            if user_express_info is not None:
                user_express_info_uuid = user_express_info.uuid

            user_express.default_uuid = user_express_info_uuid
            user_express.save()

        if count <= 0:
            raise UserExpressNullErr
        return JsonResponse(
            {"code": 0, "msg": "ok"},
            status=status.HTTP_200_OK,
        )


class UserExpressListView(View):
    @login_auth
    def get(self, request, *args, **kwargs):
        user = get_current_user(request, False)
        _user_express_info_list = UserExpressInfo.objects.filter(deleted=False).filter(
            user_uuid=user.uuid
        )
        _user_express_info_list_data = []
        for user_express_info in _user_express_info_list:
            _user_express_info_list_data.append(
                UserExpressInfoSerializer(user_express_info).data
            )
        return JsonResponse(
            {"code": 0, "msg": "ok", "data": {"list": _user_express_info_list_data}},
            status=status.HTTP_200_OK,
        )


class UserDeliveryListView(View):
    @login_auth
    def get(self, request, *args, **kwargs):
        state_resolver = EnumFilterResolver(UserDeliveryOrderState)
        state = state_resolver.resolve_argument("state", request)
        pagination = JQPagination(UserDeliveryOrderListSerializer)
        user = get_current_user(request, False)
        _query_set = UserDeliveryOrder.objects.filter(deleted=False).filter(
            user_uuid=user.uuid
        )
        if state is not None:
            _query_set = _query_set.filter(state=state)

        _data = pagination.paginate(_query_set, request)
        return JsonResponse(
            {"code": 0, "msg": "ok", "data": _data},
            status=status.HTTP_200_OK,
        )


class UserDeliveryDetailedView(View):
    _filters = {
        "uuid": StringFilterResolver(required=True),
    }

    @login_auth
    def get(self, request, *args, **kwargs):
        user = get_current_user(request, False)
        _query_set = UserDeliveryOrder.objects.filter(deleted=False).filter(
            user_uuid=user.uuid
        )
        _query_set = join_filters(_query_set, request, self._filters)

        user_delivery_order = _query_set.first()

        if user_delivery_order is None:
            raise UserDeliveryNullErr

        return JsonResponse(
            {
                "code": 0,
                "msg": "ok",
                "data": UserDeliveryOrderDetailedSerializer(user_delivery_order).data,
            },
            status=status.HTTP_200_OK,
        )


class UserConfirmDeliveryView(View):
    @login_auth
    @transaction.atomic()
    def put(self, request, *args, **kwargs):
        data = JSONParser().parse(request)
        uuid = data.get("uuid")
        if uuid is None or uuid == "":
            raise UserDeliveryNullErr

        user = get_current_user(request, False)
        _query_set = (
            UserDeliveryOrder.objects.filter(deleted=False)
            .filter(user_uuid=user.uuid)
            .filter(state=UserDeliveryOrderState.delivered)
            .filter(uuid=uuid)
        )

        user_delivery_order = _query_set.select_for_update().first()

        if user_delivery_order is None:
            raise UserDeliveryNullErr

        if user_delivery_order.state != UserDeliveryOrderState.delivered:
            raise UserDeliveryNullErr

        user_delivery_order.state = UserDeliveryOrderState.received
        user_delivery_order.receive_datetime = datetime.now()

        user_delivery_order.save()

        return JsonResponse(
            {
                "code": 0,
                "msg": "ok",
                "data": UserDeliveryOrderDetailedSerializer(user_delivery_order).data,
            },
            status=status.HTTP_200_OK,
        )
